#!/usr/bin/perl
# apk add perl-libwww perl-json

use strict;
use warnings;
use 5.016;

use LWP::UserAgent;
use LWP::ConnCache;
use CPAN::Meta;
use Module::CoreList;
use JSON;
use Text::Wrap qw(wrap $columns);
use List::Util qw (uniq);
use File::Basename qw(basename dirname);
use URI;

my $license_mappings = {
    "perl_5"     => "GPL-1.0-or-later OR Artistic-1.0-Perl",
    "artistic_2" => "Artistic-2.0",
    "gpl_2"      => "GPL-2.0-only",
    "gpl_3"      => "GPL-3.0-only",
    "mit"        => "MIT",
    "apache_2_0" => "Apache-2.0",
};

my $package_mappings = {
    "LWP"         => "perl-libwww",
    "libwww-perl" => "perl-libwww",
    "TermReadKey" => "perl-term-readkey",
    "perl-ldap"   => "perl-ldap",
    "PerlIO-gzip" => "perl-io-gzip",
    "ControlX10-CM11" => "perl-control-x10",
    "File-RsyncP" => "perl-file-rsync",
    "Perl-Critic" => "perl-critic",
    "Perl-Tidy"   => "perl-tidy",
    "ack"         => "ack",
    "Mail-SpamAssassin" => "spamassassin",
};
our $packager = "";
my $template = <<'EOF';
# Automatically generated by apkbuild-cpan, template 4
[% authors %]
pkgname=[% pkgname %]
pkgver=[% pkgver %]
pkgrel=[% pkgrel %]
# _pkgreal is used by apkbuild-cpan to find modules at MetaCpan
_pkgreal=[% pkgreal %]
pkgdesc="Perl module for [% pkgreal %]"
provides="[% provides %]"
replaces="[% replaces %]"
url="https://metacpan.org/release/[% pkgreal %]/"
arch="noarch"
options="[% options %]"[% options_comment %]
license="GPL-1.0-or-later OR Artistic-1.0-Perl"
depends="perl"
makedepends=""
checkdepends=""
subpackages="$pkgname-doc"
source="[% source %]"
builddir="[% builddir %]"

build() {
	:
}

check() {
	:
}

package() {
	:
}

EOF

our $ua   = LWP::UserAgent->new();
our $json = JSON->new;
$ua->env_proxy;
$ua->conn_cache( LWP::ConnCache->new() );

sub read_file {
    my ($filename) = @_;
    local $/;
    open my $fh, "<", $filename or die "could not open $filename: $!";
    return <$fh>;
}

sub read_assignments_from_file {
    my ($filename) = @_;
    return () if ( !-e $filename );
    my $text  = read_file($filename);
    my %sline = $text =~ /^(\w+)\s*=\s*([^\"\n]*)$/mg;
    my %mline = $text =~ /^(\w+)\s*=\s*\"([^\"]*)\"$/mg;
    my %hash  = ( %sline, %mline );

    return \%hash if $filename ne 'APKBUILD';
    my $authors = join( "\n",
        $text =~ /^# Contributor: .*$/mg,
        $text =~ /^# Maintainer: .*$/mg );
    $hash{'authors'} = $authors if length($authors) > 1;

    my $options = $text =~ m/^options=\"(.*)\"(.*)$/mg;
    $hash{'options'} = "$1" if length($options) >= 1;
    $hash{'options_comment'} = "$2" if length($options) >= 1;

    return \%hash;
}

sub map_cpan_to_apk {
    my ($cpan_distrib) = @_;
    return $package_mappings->{$cpan_distrib}
      if exists $package_mappings->{$cpan_distrib};

    # most packages are named according to the
    # distribution name
    return 'perl-' . lc $cpan_distrib;
}

sub read_apkbuild {
    return read_assignments_from_file("APKBUILD");
}

sub format_line {
    my $line = shift;
    return "\t" . $line . "\n";
}

sub format_source {
    my $srcurl   = shift;
    my $orig_src = shift;

    $orig_src =~ s/^\n//mg;

    my @sources = split (/\n/m, $orig_src);

    return $srcurl if scalar @sources le 1;

    my $source = format_line($srcurl);

    shift @sources;
    my $patches = undef;
    for my $patch (@sources) {
        $patch =~ s/\t//g;
        next if $patch eq "";
        $patches .= format_line($patch);
    }

    return "\n" . $source . (defined $patches ? $patches : '') . "\t";
}

sub write_apkbuild {
    my ( $distdata, $apkbuild, $moddata ) = @_;

    my $authors  = undef;
    my $replaces = undef;
    my $provides = undef;
    my $pkgrel   = 0;
    my $options = undef;
    my $options_comment = undef;
    my $orig_source = undef;
    if ( defined $apkbuild ) {
        $authors  = $apkbuild->{authors};
        $provides = $apkbuild->{provides};
        $replaces = $apkbuild->{replaces};
        $pkgrel   = $apkbuild->{pkgrel};
        $options  = $apkbuild->{options} if defined $apkbuild->{options};
        $options_comment  = $apkbuild->{options_comment} if defined $apkbuild->{options_comment};
        $orig_source      = $apkbuild->{source};
        if ( $apkbuild->{pkgver} eq $moddata->{version} ) {
            $pkgrel++;
        }
    }

    my $builddir;

    my $srcurl = $moddata->{download_url};
    my $filename = (URI->new($srcurl)->path_segments)[-1];

    my $pkgreal = $moddata->{distribution};
    my $pkgver = $moddata->{version} =~ s/^[^0-9]+//r;
    if ( $filename =~ m/$pkgreal-$pkgver/ ) {
        $builddir = "\$srcdir/\$_pkgreal-\$pkgver";
    } elsif ( $filename =~ m/$pkgreal-v${pkgver}/ ) {
        $builddir = "\$srcdir/\$_pkgreal-v\$pkgver";
    } else {
        $builddir = "\$srcdir/\$_pkgreal-" . $moddata->{version};
    }

    my %repl = (
        authors => (
            $authors
              or "# Contributor: $packager\n# Maintainer: $packager"
        ),
        pkgname  => map_cpan_to_apk( $moddata->{distribution} ),
        pkgreal  => $pkgreal,
        pkgver   => $pkgver,
        pkgrel   => $pkgrel,
        source   => format_source($srcurl, $orig_source),
        pkgdesc  => $distdata->{abstract},
        provides => ( $provides or '' ),
        replaces => ( $replaces or '' ),
        builddir => $builddir,
        options  => ( $options or '' ),
        options_comment => ( $options_comment or '' ),
    );
    $repl{source} =~ s/$repl{pkgver}/\$pkgver/g;
    $template =~ s/\[% (.*?) %\]/$repl{$1}/g;

    open my $fh, '>', "APKBUILD" or die;
    print $fh $template;
    close $fh;

    say "Wrote $repl{pkgname}/APKBUILD";
}

sub query_metacpan {
    my ($type, $name) = @_;

    my $response = $ua->get("https://fastapi.metacpan.org/$type/$name");
    $response->is_success
      or die $response->status_line
      . " unable to find $name, verify Perl Module name in APKBUILD\n";

    my $data = $json->decode( $response->decoded_content );
    $data->{error}
      and die "Error trying to locate $name: $data->{error}\n";

    return $data;
}

sub parse_deps {
    my ($reqs) = @_;
    my $distfiles = {};
    my $deps       = "";
    my $reqmodlist = "";

    #Get list of unique required modules from all parameters
    foreach $reqs (@_) {
        for my $module ( $reqs->required_modules ) {
            $reqmodlist .= "$module " unless $reqmodlist =~ m/^$module$/;
        }
    }

    # Check add the require module to $dep if not part of core perl
    foreach my $module ( split " ", $reqmodlist ) {
        next if $module eq 'perl';
        if ( Module::CoreList->is_core($module) ) {
            my $perlver = Module::CoreList->first_release($module);
            say "    $module is part of core perl since $perlver.";
            next;
        }

        # map module name to package name
        my $moddata = query_metacpan( module => $module );
        $distfiles->{$module} = $moddata->{distribution};
    }

    # map package names to alpine packages
    foreach my $module ( sort keys %{$distfiles} ) {
        my $pkgname = map_cpan_to_apk( $distfiles->{$module} );
        $deps .= "$pkgname " unless $deps =~ m/\b$pkgname\b/;
    }
    $deps =~ s/\h+/ /g;
    $deps =~ s/ $//;
    return defined $deps ? $deps : '';
}

sub prepare_tree {
    system("abuild checksum unpack prepare") == 0
      or die "abuild checksum failed";
}

sub update_functions {
    my $apkbuild = read_apkbuild;
    my $pkgver = $apkbuild->{'pkgver'};
    my $build_pl_found = glob("src/*${pkgver}/Build.PL");
    my $build_func;
    my $check_func;
    my $package_func;

    my $text = read_file "APKBUILD";
    if ( $build_pl_found ) {
        $build_func = <<'EOF';
build() {
	export CFLAGS=$(perl -MConfig -E 'say $Config{ccflags}')
	perl Build.PL \
		--installdirs=vendor \
		--create_packlist=0
	./Build
}
EOF
        $package_func = <<'EOF';
package() {
	./Build install --destdir="$pkgdir"
}
EOF
        $check_func = <<'EOF';
check() {
	./Build test
}
EOF
    }
    else {
        $build_func = <<'EOF';
build() {
	export CFLAGS=$(perl -MConfig -E 'say $Config{ccflags}')
	PERL_MM_USE_DEFAULT=1 perl -I. Makefile.PL \
		INSTALLDIRS=vendor \
		NO_PACKLIST=1 \
		NO_PERLLOCAL=1
	make
}
EOF
        $package_func = <<'EOF';
package() {
	make DESTDIR="$pkgdir" install
}
EOF
        $check_func = <<'EOF';
check() {
	export CFLAGS=$(perl -MConfig -E 'say $Config{ccflags}')
	make test
}
EOF
    }

    if ( length(`find src/*$pkgver/lib -name '*.pod'`) ) {
        $package_func .= <<'EOF';

doc() {
	local file; find "$pkgdir" -name "*.pod" | while read -r file; do
		amove "${file#"$pkgdir"}"
	done
	default_doc
}
EOF
    }

    $text =~ s/^build\(\) \{.*?^\}\n/$build_func/smg
      or die "Can't replace build function APKBUILD";
    $text =~ s/^package\(\) \{.*?^\}\n/$package_func/smg
      or die "Can't replace package function APKBUILD";
    $text =~ s/^check\(\) \{.*?^\}\n/$check_func/smg
      or die "Can't replace check function APKBUILD";

    open my $fh, '>', "APKBUILD" or die;
    print $fh $text;
    close $fh;
}

sub sort_pkgs_by_orig {
    my $sort_order = shift;
    my $list       = shift;

    return '' if !defined $list;
    my @array_to_sort = split / /, $list;

    s/[\t\n\r\f]/ /g
      for $sort_order;    # remove embedded new lines from sort order
    s/\h+/ /g for $sort_order;    # remove embedded spaces from sort order

    my @sort_order = split / /, $sort_order;

    #get order of order by string
    my $count = 0;
    my %position_of;
    $position_of{$_} = $count++ for @sort_order;

    my %sorted;                   # holds the position of array to sort

    foreach (@array_to_sort) {
        my $pos = $position_of{$_};
        if ( !defined $pos ) {

            # not found in sort order so add to the end
            $sorted{$_} = $count;
            $count++;
        }
        else {
            $sorted{$_} = $pos;
        }
    }

    my @tmp;    # hold array of sorted in position order

    foreach my $name ( sort { $sorted{$a} <=> $sorted{$b} } keys %sorted ) {
        push @tmp, $name;
    }

    # remove any duplicates
    uniq @tmp;

    return join( " ", @tmp );
}

sub format_depends {
    my $deps = shift;

    return '' if !defined $deps;
    $columns = 102;

    $deps =~ s/ {2,}/ /g;
    $deps =~ s/^\s//g;
    $deps =~ s/\s$//g;

    if ( length($deps) >= $columns ) {
        $deps = wrap( "\t", "\t", $deps );
    }
    $deps =~ s/\s$//g;

    if ( length($deps) >= $columns ) {
        $deps = "\n" . $deps . "\n\t";
    }
    return $deps;
}

sub do_depends {
    my $modver      = shift;
    my $oldapkbuild = shift;
    my $apkbuild    = read_apkbuild;

    my $metaprefix = '';
    if ( exists $apkbuild->{'_realname'} ) {
        $metaprefix = "src/" . $apkbuild->{'_realname'};
    }
    elsif ( exists $apkbuild->{'_pkgreal'} ) {
        $metaprefix = "src/" . $apkbuild->{'_pkgreal'};
    }
    elsif ( exists $apkbuild->{'_pkgname'} ) {
        $metaprefix = "src/" . $apkbuild->{'_pkgname'};
    }
    elsif ( exists $apkbuild->{'_name'} ) {
        $metaprefix = "src/" . $apkbuild->{'_name'};
    }
    elsif ( exists $apkbuild->{'_realpkgname'} ) {
        $metaprefix =
          "src/" . $apkbuild->{'_realpkgname'};
    }
    elsif ( exists $apkbuild->{'_pkg_real'} ) {
        $metaprefix = "src/" . $apkbuild->{'_pkg_real'};
    }
    else {
        die
"Unable to find meta file directory - check APKBUILD Perl Module Name";
    }

    $modver = defined($modver) ? $modver : $apkbuild->{'pkgver'};
    $modver =~ s/v//g;

    # try with partial metaprefix
    my @metafiles = glob("
        $metaprefix-*${modver}/*META.json
        $metaprefix-*${modver}/*META.yml
    ");

    my $build_path = glob("
        src/*${modver}/Build.PL
        src/*${modver}/Makefile.PL
    ");

    if ( @metafiles ) {
        $metaprefix = dirname($metafiles[0]);
    } elsif ( $build_path ) {
        $metaprefix = dirname($build_path);
        my $build_file = basename($build_path);
        system("cd $metaprefix && perl -I. $build_file");

        # try again with full metaprefix
        push @metafiles, glob("
            $metaprefix/*META.json
            $metaprefix/*META.yml
        ");
    } else {
        die "Unable to find meta, makefile, and build.pl - cannot proceed"
    }

    die "No meta files found after executing $build_path" unless @metafiles;

    my $builddir = do {
        my $pkgreal = $apkbuild->{'_pkgreal'};
        my $oldbuilddir = $apkbuild->{builddir};
        my $newbuilddir = $metaprefix;

        $newbuilddir =~ s/src/\$srcdir/;
        $newbuilddir =~ s/$pkgreal/\$_pkgreal/;
        $newbuilddir =~ s/$modver/\$pkgver/;

        $newbuilddir eq $oldbuilddir ? undef : $newbuilddir
    };

    my $meta;

    foreach
      my $metafile ( @metafiles )
    {
        if ( -e "$metafile" ) {
            say "Using meta information from $metafile";
            $meta = CPAN::Meta->load_file("$metafile");
            last;
        }
    }

    my $deps;
    my $abstract;
    my $license;
    if ($meta) {
        $license = join " OR ",
          map { $license_mappings->{$_} or $_ } $meta->license;
        say "License: $license";

        $abstract = $meta->abstract;
        say "Abstract: $abstract";

        $deps = parse_deps(
            $meta->effective_prereqs->requirements_for( 'runtime', 'requires' ) );
    }

    if ( defined $oldapkbuild->{'depends'} ) {
        if ( defined $oldapkbuild->{'cpandepends'} ) {
            $oldapkbuild->{'depends'} =~
              s/\$cpandepends/$oldapkbuild->{'cpandepends'}/g;
        }
        my @libs = split /\s+/, $oldapkbuild->{'depends'};
        if ( @libs ) {
            my $libs = join ' ',
              grep { not (m/perl\-\w+[-\w+]+/ or ($_ eq 'perl')) } @libs;
            $deps .= " " . $libs if defined $deps;
        }
        $deps = sort_pkgs_by_orig( $oldapkbuild->{'depends'}, $deps );
    }

    if ( defined $deps && $deps eq '' ) {
        if (defined $oldapkbuild->{'depends'} && ! $meta ) {
            $deps = $oldapkbuild->{'depends'};
        } else {
            $deps = "perl";
        }
    }
    else {
        $deps = format_depends( "perl " . $deps ) if defined $deps;
    }

    my $makedeps = '';
    if ($meta) {
        say "CPAN runtime Required: $deps";
        say "CPAN runtime Recommended: "
          . parse_deps(
            $meta->effective_prereqs->requirements_for( 'runtime', 'recommends' ) );

        $makedeps = parse_deps(
            $meta->effective_prereqs->requirements_for( 'configure', 'requires' ),
            $meta->effective_prereqs->requirements_for( 'configure', 'recommends' ),
            $meta->effective_prereqs->requirements_for( 'build', 'requires' ),
            $meta->effective_prereqs->requirements_for( 'build', 'recommends' )
        );

        if ( -e "$metaprefix/Build.PL" ) {
            $makedeps = "$makedeps perl-module-build"
              unless $makedeps =~ m/^perl-module-build$/;
        }

    }
    if ( defined $oldapkbuild->{'makedepends'} ) {
        if ( defined $oldapkbuild->{'cpanmakedepends'} ) {
            $oldapkbuild->{'makedepends'} =~
              s/\$cpanmakedepends/$oldapkbuild->{'cpanmakedepends'}/g;
        }
        my @libs = split /\s+/, $oldapkbuild->{'makedepends'};
        if ( @libs ) {
            my $libs = join ' ', grep { not (m/perl\-\w+[-\w+]+/) } @libs;
            $makedeps .= " " . $libs;
        }
        $makedeps =
          sort_pkgs_by_orig( $oldapkbuild->{'makedepends'}, $makedeps );
    }

    my $has_xs = length(`find $metaprefix -name '*.xs'`);

    my $perldev = $has_xs ? "perl-dev" : '';
    if ( defined $makedeps && $makedeps eq '' ) {
        if (defined $oldapkbuild->{'makedepends'} && ! $meta) {
            $makedeps = $oldapkbuild->{'makedepends'};
            my @tmp = split(" ", $makedeps);
            @tmp = grep ! /$perldev/, @tmp if ! $has_xs;
            $makedeps = format_depends(join(" ", @tmp));
        } else {
            $makedeps = $perldev;
        }
    }
    else {
        $makedeps = format_depends( $perldev . " " . $makedeps );
    }
    $makedeps =~ s/ +$//g;

    my $checkdeps;
    if ($meta) {
        say "CPAN build deps: $makedeps";
        say "    CPAN build requires: "
          . parse_deps(
            $meta->effective_prereqs->requirements_for( 'configure', 'requires' ),
            $meta->effective_prereqs->requirements_for( 'build', 'requires' )
          );
        say "    CPAN build recommends: "
          . parse_deps(
            $meta->effective_prereqs->requirements_for( 'configure', 'recommends' ),
            $meta->effective_prereqs->requirements_for( 'build', 'recommends' )
          );

        $checkdeps = parse_deps(
            $meta->effective_prereqs->requirements_for( 'test', 'requires' ),
            $meta->effective_prereqs->requirements_for( 'test', 'recommends' )
        );
    }

    if ( defined $oldapkbuild->{'checkdepends'} ) {
        if ( defined $oldapkbuild->{'cpancheckdepends'} ) {
            $oldapkbuild->{'checkdepends'} =~
              s/\$cpancheckdepends/$oldapkbuild->{'cpancheckdepends'}/g;
        }
        my @libs = split /\s+/, $oldapkbuild->{'checkdepends'};
        if ( @libs ) {
            my $libs = join ' ', grep { not (m/perl\-\w+[-\w+]+/) } @libs;
            $checkdeps .= " " . $libs;
        }
        $checkdeps =
          sort_pkgs_by_orig( $oldapkbuild->{'checkdepends'}, $checkdeps );
    }

    if ( defined $checkdeps && $checkdeps eq '' ) {
        if (defined $oldapkbuild->{'checkdeps'} && ! $meta) {
            $checkdeps = $oldapkbuild->{'checkdeps'};
        }
    } else {
        $checkdeps = format_depends($checkdeps);
    }

    say "CPAN check deps: $checkdeps";

    my $text = read_file "APKBUILD";
    if ( $abstract && $abstract ne 'unknown' ) {
        $abstract =~ s/"/\\"/g;
        $abstract =~ s/[.\s]+$//;

        $text =~ s/^pkgdesc=\"([^\"]*)\"$/pkgdesc=\"$abstract\"/mg
          or die "Can't find pkgdesc line in APKBUILD";
    }

    if ( exists $oldapkbuild->{'arch'} ) {
        # Prevent removal of empty arch variable for disabled aports
        my $subst_arch = $oldapkbuild->{'arch'}
          ? '"' . $oldapkbuild->{'arch'} . '"'
          : "";

        $text =~ s/^arch=\"([^\"]*)\"$/arch=$subst_arch/mg
          or die "Can't find arch line in APKBUILD";
    } elsif ( $has_xs ) {
        $text =~ s/^arch=\"([^\"]*)\"$/arch="all"/mg
          or die "Can't find arch line in APKBUILD";
    }

    if ( defined $license && $license ne 'unknown' ) {
        $text =~ s/^license=\"([^\"]*)\"$/license=\"$license\"/mg
          or die "Can't find license line in APKBUILD";
    }
    $text =~ s/^depends=\"([^\"]*)\"$/depends=\"$deps\"/mg
      or $text =~ s/(license=.*\n)/$1depends=\"$deps\"\n/gm
      or die "Can't insert depends line in APKBUILD" if defined $deps;

    $text =~ s/^makedepends=\"([^\"]*)\"$/makedepends=\"$makedeps\"/mg
      or $text =~ s/(depends=.*\n)/$1makedepends=\"$makedeps\"\n/gm
      or die "Can't insert makedepends line in APKBUILD" if defined $makedeps;

    $text =~ s/^checkdepends=\"([^\"]*)\"$/checkdepends=\"$checkdeps\"/mg
      or $text =~ s/(makedepends=.*\n)/$1checkdepends=\"$checkdeps\"\n/gm
      or die "Can't insert checkdepends line in APKBUILD" if defined $checkdeps;

    if (defined $builddir) {
        print "\n\$builddir redefined:\n\tOLD: '", $apkbuild->{builddir},
            "', NEW: '", $builddir, "'\n";

        $text =~ s/^builddir=\"([^\"]*)\"/builddir="$builddir"/mg;
    }

    # remove empty variables
    $text =~ s/.*="".{0,}\n//g;

    open my $fh, '>', "APKBUILD" or die;
    print $fh $text;
    close $fh;
}

sub get_data {
    my $apkbuild = read_apkbuild;
    my $pkgreal  = '';

    if ( exists $apkbuild->{_realname} ) {
        $pkgreal = $apkbuild->{_realname};
    }
    elsif ( exists $apkbuild->{_pkgreal} ) {
        $pkgreal = $apkbuild->{_pkgreal};
    }
    elsif ( exists $apkbuild->{_pkgname} ) {
        $pkgreal = $apkbuild->{_pkgname};
    }
    elsif ( exists $apkbuild->{_name} ) {
        $pkgreal = $apkbuild->{_name};
    }
    elsif ( exists $apkbuild->{_realpkgname} ) {
        $pkgreal = $apkbuild->{_realpkgname};
    }
    elsif ( exists $apkbuild->{_pkg_real} ) {
        $pkgreal = $apkbuild->{_pkg_real};
    }
    else {
        my $module       = '';
        my $distribution = '';
        while ( ( my $key, my $value ) = each(%$apkbuild) ) {

            # Do not parse any depends lines to not find incorrect module
            if ( $key =~ m/.*depends.*/ ) {
                next;
            }

            # Try to find a perl module name in APKBUILD
            if ( $value =~ m/((\w+::)+\w+)/g ) {

                # Match Perl Module names containing ::
                $module .= "$1 " unless $module =~ m/$1/;
            }
            elsif ( $value =~ m/(([A-Z]\w+-)+\w+)/ ) {

                # Match possible distribution names with -
                $distribution .= "$1 " unless $distribution =~ m/ *$1 /;
            }
            elsif ( $value =~ m/.*release\/([A-Z]\w+).*/ ) {

                # Match Single Word Perl Module Name after release in URL?
                $distribution .= "$1 " unless $distribution =~ m/ *$1 /;
            }
        }

        # Want to try the traditional Module::Name first
        my $list = $module . $distribution;
        foreach ( split / /, $list ) {
            my $type = '';
            if ( $_ =~ m/::/ ) {
                $type = 'module';
            }
            else {
                $type = 'release';
            }

            my $moddata;
            eval { $moddata = query_metacpan( $type => $_ ); };
            next if $@
              or ref $moddata ne 'HASH'
              or not $moddata->{distribution};

            $pkgreal = $moddata->{distribution};
            last;
        }
    }

    $pkgreal =~ s/-\$pkgver//g;

    my $distdata = query_metacpan( release => $pkgreal );

    my $moddata = query_metacpan( module => $distdata->{main_module} );

    return ( $apkbuild, $distdata, $moddata );
}

my $abuild_conf = read_assignments_from_file("/etc/abuild.conf");
$packager = $abuild_conf->{PACKAGER} if $abuild_conf->{PACKAGER};

my $user_abuild_conf =
  read_assignments_from_file( $ENV{"HOME"} . "/.abuild/abuild.conf" );
$packager = $user_abuild_conf->{PACKAGER} if $user_abuild_conf->{PACKAGER};

my $command = $ARGV[0] // '';

if ( $command eq "create" ) {
    my $module = $ARGV[1];
    $module or die "Module name is a mandatory argument";

    my $moddata = query_metacpan( module => $module );

    my $distdata = query_metacpan( release => $moddata->{distribution} );

    my $apkname = map_cpan_to_apk $distdata->{metadata}{name};
    mkdir $apkname;
    chdir $apkname;
    write_apkbuild( $distdata, undef, $moddata );
    prepare_tree;
    update_functions;
    do_depends $moddata->{version};
}
elsif ( $command eq "recreate" ) {

    #TODO: likely should keep pkgrel the same on recreate
    my ( $apkbuild, $distdata, $moddata ) = get_data;
    my $pkgver = $moddata->{version} =~ s/^[^0-9]+//r;
    if ( $pkgver ne $apkbuild->{pkgver} ) {

        #Reset pkgrel on upgrade on recreate
        say "Upgrading CPAN module from $apkbuild->{pkgver} to $pkgver";
        $apkbuild->{pkgrel} = 0;
    }
    write_apkbuild( $distdata, $apkbuild, $moddata );
    prepare_tree;
    update_functions;
    do_depends( $moddata->{version}, $apkbuild );
}
elsif ( $command eq "upgrade" ) {
    my ( $apkbuild, $distdata, $moddata ) = get_data;

    my $pkgver = $moddata->{version} =~ s/^[^0-9]+//r;
    if ( $pkgver ne $apkbuild->{pkgver} ) {
        say "Upgrading CPAN module from $apkbuild->{pkgver} to $pkgver";

        my $text = read_file "APKBUILD";
        $text =~ s/^pkgver=(.*)$/pkgver=$pkgver/mg
          or die "Can't find pkgver line in APKBUILD";
        $text =~ s/^pkgrel=(.*)$/pkgrel=0/mg;

        #FIXME: review whether this works over time
        #       It deletes the blank line before the checksum
        #       So prepare_tree does not insert extra blank line
        $text =~ s/\n^(.*sums=.*\n)/$1/mg;
        open my $fh, '>', "APKBUILD" or die;
        say $fh $text;
        close $fh;
        prepare_tree;
        do_depends( $moddata->{version}, $apkbuild );
    }
    else {
        say "Up-to-date with CPAN";
    }
}
elsif ( $command eq "check" ) {
    my ( $apkbuild, $distdata, $moddata ) = get_data;
    my $pkgver = $moddata->{version} =~ s/^[^0-9]+//r;
    say
"$apkbuild->{pkgname}: Latest version: $pkgver Packaged version: $apkbuild->{pkgver}";
    if ( $pkgver ne $apkbuild->{pkgver} ) {
        exit(1);
    }
}
elsif ( $command eq "update" ) {
    prepare_tree;
    do_depends;
}
else {
    say
"Usage: apkbuild-cpan [create <Module::Name> | check | recreate | update | upgrade]";
    exit;
}
